using System;
using System.Collections.Generic;
using System.Windows;

/*
 * $Id: MetaState.cs 125 2010-02-21 22:51:06Z psoares33 $
 * 
 *
 * This file is part of the iText project.
 * Copyright (c) 1998-2009 1T3XT BVBA
 * Authors: Bruno Lowagie, Paulo Soares, et al.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
 * http://itextpdf.com/terms-of-use/
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License,
 * you must retain the producer line in every PDF that is created or manipulated
 * using iText.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the iText software without
 * disclosing the source code of your own applications.
 * These activities include: offering paid services to customers as an ASP,
 * serving PDFs on the fly in a web application, shipping iText with a closed
 * source product.
 *
 * For more information, please contact iText Software Corp. at this
 * address: sales@itextpdf.com
 */

namespace iTextSharp.text.pdf.codec.wmf
{
    public class MetaState
    {

        public static int TA_NOUPDATECP = 0;
        public static int TA_UPDATECP = 1;
        public static int TA_LEFT = 0;
        public static int TA_RIGHT = 2;
        public static int TA_CENTER = 6;
        public static int TA_TOP = 0;
        public static int TA_BOTTOM = 8;
        public static int TA_BASELINE = 24;

        public static int TRANSPARENT = 1;
        public static int OPAQUE = 2;

        public static int ALTERNATE = 1;
        public static int WINDING = 2;

        public Stack<MetaState> savedStates;
        public List<MetaObject> MetaObjects;
        public Point currentPoint;
        public MetaPen currentPen;
        public MetaBrush currentBrush;
        public MetaFont currentFont;
        public BaseColor currentBackgroundColor = BaseColor.WHITE;
        public BaseColor currentTextColor = BaseColor.BLACK;
        public int backgroundMode = OPAQUE;
        public int polyFillMode = ALTERNATE;
        public int lineJoin = 1;
        public int textAlign;
        public int offsetWx;
        public int offsetWy;
        public int extentWx;
        public int extentWy;
        public float scalingX;
        public float scalingY;


        /** Creates new MetaState */
        public MetaState()
        {
            savedStates = new Stack<MetaState>();
            MetaObjects = new List<MetaObject>();
            currentPoint = new Point(0, 0);
            currentPen = new MetaPen();
            currentBrush = new MetaBrush();
            currentFont = new MetaFont();
        }

        public MetaState(MetaState state)
        {
            metaState = state;
        }

        public MetaState metaState
        {
            set
            {
                savedStates = value.savedStates;
                MetaObjects = value.MetaObjects;
                currentPoint = value.currentPoint;
                currentPen = value.currentPen;
                currentBrush = value.currentBrush;
                currentFont = value.currentFont;
                currentBackgroundColor = value.currentBackgroundColor;
                currentTextColor = value.currentTextColor;
                backgroundMode = value.backgroundMode;
                polyFillMode = value.polyFillMode;
                textAlign = value.textAlign;
                lineJoin = value.lineJoin;
                offsetWx = value.offsetWx;
                offsetWy = value.offsetWy;
                extentWx = value.extentWx;
                extentWy = value.extentWy;
                scalingX = value.scalingX;
                scalingY = value.scalingY;
            }
        }

        public void AddMetaObject(MetaObject obj)
        {
            for (int k = 0; k < MetaObjects.Count; ++k)
            {
                if (MetaObjects[k] == null)
                {
                    MetaObjects[k] = obj;
                    return;
                }
            }
            MetaObjects.Add(obj);
        }

        public void SelectMetaObject(int index, PdfContentByte cb)
        {
            MetaObject obj = MetaObjects[index];
            if (obj == null)
                return;
            int style;
            switch (obj.Type)
            {
                case MetaObject.META_BRUSH:
                    currentBrush = (MetaBrush)obj;
                    style = currentBrush.Style;
                    if (style == MetaBrush.BS_SOLID)
                    {
                        BaseColor color = currentBrush.Color;
                        cb.SetColorFill(color);
                    }
                    else if (style == MetaBrush.BS_HATCHED)
                    {
                        BaseColor color = currentBackgroundColor;
                        cb.SetColorFill(color);
                    }
                    break;
                case MetaObject.META_PEN:
                    {
                        currentPen = (MetaPen)obj;
                        style = currentPen.Style;
                        if (style != MetaPen.PS_NULL)
                        {
                            BaseColor color = currentPen.Color;
                            cb.SetColorStroke(color);
                            cb.SetLineWidth(Math.Abs((float)currentPen.PenWidth * scalingX / extentWx));
                            switch (style)
                            {
                                case MetaPen.PS_DASH:
                                    cb.SetLineDash(18, 6, 0);
                                    break;
                                case MetaPen.PS_DASHDOT:
                                    cb.SetLiteral("[9 6 3 6]0 d\n");
                                    break;
                                case MetaPen.PS_DASHDOTDOT:
                                    cb.SetLiteral("[9 3 3 3 3 3]0 d\n");
                                    break;
                                case MetaPen.PS_DOT:
                                    cb.SetLineDash(3, 0);
                                    break;
                                default:
                                    cb.SetLineDash(0);
                                    break;
                            }
                        }
                        break;
                    }
                case MetaObject.META_FONT:
                    {
                        currentFont = (MetaFont)obj;
                        break;
                    }
            }
        }

        public void DeleteMetaObject(int index)
        {
            MetaObjects[index] = null;
        }

        public void SaveState(PdfContentByte cb)
        {
            cb.SaveState();
            MetaState state = new MetaState(this);
            savedStates.Push(state);
        }

        public void RestoreState(int index, PdfContentByte cb)
        {
            int pops;
            if (index < 0)
                pops = Math.Min(-index, savedStates.Count);
            else
                pops = Math.Max(savedStates.Count - index, 0);
            if (pops == 0)
                return;
            MetaState state = null;
            while (pops-- != 0)
            {
                cb.RestoreState();
                state = savedStates.Pop();
            }
            metaState = state;
        }

        public void Cleanup(PdfContentByte cb)
        {
            int k = savedStates.Count;
            while (k-- > 0)
                cb.RestoreState();
        }

        public float TransformX(int x)
        {
            return ((float)x - offsetWx) * scalingX / extentWx;
        }

        public float TransformY(int y)
        {
            return (1f - ((float)y - offsetWy) / extentWy) * scalingY;
        }

        public float ScalingX
        {
            set
            {
                this.scalingX = value;
            }
        }

        public float ScalingY
        {
            set
            {
                this.scalingY = value;
            }
        }

        public int OffsetWx
        {
            set
            {
                this.offsetWx = value;
            }
        }

        public int OffsetWy
        {
            set
            {
                this.offsetWy = value;
            }
        }

        public int ExtentWx
        {
            set
            {
                this.extentWx = value;
            }
        }

        public int ExtentWy
        {
            set
            {
                this.extentWy = value;
            }
        }

        public float TransformAngle(float angle)
        {
            float ta = scalingY < 0 ? -angle : angle;
            return (float)(scalingX < 0 ? Math.PI - ta : ta);
        }

        public Point CurrentPoint
        {
            get
            {
                return currentPoint;
            }

            set
            {
                currentPoint = value;
            }
        }

        public MetaBrush CurrentBrush
        {
            get
            {
                return currentBrush;
            }
        }

        public MetaPen CurrentPen
        {
            get
            {
                return currentPen;
            }
        }

        public MetaFont CurrentFont
        {
            get
            {
                return currentFont;
            }
        }

        /** Getter for property currentBackgroundColor.
         * @return Value of property currentBackgroundColor.
         */
        public BaseColor CurrentBackgroundColor
        {
            get
            {
                return currentBackgroundColor;
            }

            set
            {
                this.currentBackgroundColor = value;
            }
        }

        /** Getter for property currentTextColor.
         * @return Value of property currentTextColor.
         */
        public BaseColor CurrentTextColor
        {
            get
            {
                return currentTextColor;
            }

            set
            {
                this.currentTextColor = value;
            }
        }

        /** Getter for property backgroundMode.
         * @return Value of property backgroundMode.
         */
        public int BackgroundMode
        {
            get
            {
                return backgroundMode;
            }

            set
            {
                this.backgroundMode = value;
            }
        }

        /** Getter for property textAlign.
         * @return Value of property textAlign.
         */
        public int TextAlign
        {
            get
            {
                return textAlign;
            }

            set
            {
                this.textAlign = value;
            }
        }

        /** Getter for property polyFillMode.
         * @return Value of property polyFillMode.
         */
        public int PolyFillMode
        {
            get
            {
                return polyFillMode;
            }

            set
            {
                this.polyFillMode = value;
            }
        }

        public PdfContentByte LineJoinRectangle
        {
            set
            {
                if (lineJoin != 0)
                {
                    lineJoin = 0;
                    value.SetLineJoin(0);
                }
            }
        }

        public PdfContentByte LineJoinPolygon
        {
            set
            {
                if (lineJoin == 0)
                {
                    lineJoin = 1;
                    value.SetLineJoin(1);
                }
            }
        }

        public bool LineNeutral
        {
            get
            {
                return (lineJoin == 0);
            }
        }
    }
}
